﻿using System;
using Styx;
using Styx.Helpers;

using System.Linq;
using Styx.WoWInternals.World;
using Styx.CommonBot.POI;
using CommonBehaviors.Actions;
using System.Diagnostics;
using System.Drawing;
using Styx.CommonBot;
using System.Reflection;
using Styx.Pathing;
using Styx.TreeSharp;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace DayWalker.Helpers
{
    public static partial class Helper
    {
        #region Delegates

        public delegate float DynamicRangeRetriever(object context);

        public delegate WoWPoint LocationRetriever(object context);

        public delegate bool SimpleBooleanDelegate(object context);

        public delegate WoWUnit UnitSelectionDelegate(object context);

        #endregion

        public static Composite MovementMoveStop(UnitSelectionDelegate toUnit, double range)
        {
            return new Decorator(
                ret =>
               Settings.DayWalkerSettings.Instance.AutoMove &&
                
                toUnit != null &&
                toUnit(ret) != null &&
                toUnit(ret) != Me &&
                toUnit(ret).IsAlive &&
                IsMoving(Me) &&
                IsEnemy(toUnit(ret)) &&
                GetDistance(toUnit(ret)) <= range &&
                InLineOfSpellSightCheck(toUnit(ret)),
                new Action(ret =>
                {
                    Navigator.PlayerMover.MoveStop();
                    Helper.SafelyFacingTarget(Me.CurrentTarget);
                    return RunStatus.Failure;
                }));
        }

        public static Composite MovementMoveToLoS(UnitSelectionDelegate toUnit)
        {
            return new Decorator(
                ret =>
                Settings.DayWalkerSettings.Instance.AutoMove &&
                !Me.Mounted &&
              
                !Me.IsCasting &&
                    //!Me.IsChanneling &&
                toUnit != null &&
                toUnit(ret) != null &&
                toUnit(ret) != Me &&
                toUnit(ret).IsAlive &&
                IsEnemy(toUnit(ret)) &&
                (GetDistance(toUnit(ret)) > 30 ||
                 !InLineOfSpellSightCheck(toUnit(ret))),
                new Action(ret =>
                {
                    Navigator.MoveTo(toUnit(ret).Location);
                    Helper.SafelyFacingTarget(Me.CurrentTarget);
                    return RunStatus.Failure;
                }));
        }

        public static Composite MovementMoveToMelee(UnitSelectionDelegate toUnit)
        {
            return new Decorator(
                ret =>
                Settings.DayWalkerSettings.Instance.AutoMove &&
                !Me.Mounted &&
              
                !Me.IsCasting &&
                    //!Me.IsChanneling &&
                toUnit != null &&
                toUnit(ret) != null &&
                toUnit(ret) != Me &&
                toUnit(ret).IsAlive &&
                IsEnemy(toUnit(ret)) &&
                GetDistance(toUnit(ret)) > 3,
                new Action(ret =>
                {
                    Navigator.MoveTo(toUnit(ret).Location);
                    return RunStatus.Failure;
                }));
        }

        public static Composite MovementMoveBehind(UnitSelectionDelegate toUnit)
        {
            return
                new Decorator(
                    ret =>
                     Settings.DayWalkerSettings.Instance.AutoMove &&
                    !Me.Mounted &&
              
                    !Me.IsCasting &&
                        //!Me.IsChanneling &&
                    toUnit != null &&
                    toUnit(ret) != null &&
                    toUnit(ret) != Me &&
                    toUnit(ret).IsAlive &&
                        //only MovementMoveBehind if IsWithinMeleeRange
                    GetDistance(toUnit(ret)) <= 5 &&
                    !Me.IsBehind(toUnit(ret)) &&
                        //!IsTank(Me) &&
                        //Only Move again After a certain delay or target move 3 yard from original posision
                    (toUnit(ret).IsPlayer ||
                     !toUnit(ret).IsPlayer && toUnit(ret).CurrentTarget != Me && toUnit(ret).Combat),
                    new Action(ret =>
                    {
                        WoWPoint pointBehind =
                            toUnit(ret).Location.RayCast(
                                toUnit(ret).Rotation + WoWMathHelper.DegreesToRadians(150), 3f);

                        Navigator.MoveTo(pointBehind);
                        return RunStatus.Failure;
                    }));
        }
        public static Composite CreateFaceTargetBehavior(float viewDegrees = 70f, bool waitForFacing = true)
        {
            return CreateFaceTargetBehavior(ret => StyxWoW.Me.CurrentTarget, viewDegrees, waitForFacing);
        }

        public static Composite CreateFaceTargetBehavior(UnitSelectionDelegate toUnit, float viewDegrees = 100f, bool waitForFacing = true)
        {
            return new Decorator(
                ret => Settings.DayWalkerSettings.Instance.AutoMove && toUnit != null && toUnit(ret) != null
                    && !StyxWoW.Me.IsMoving
                    && !toUnit(ret).IsMe
                    && !StyxWoW.Me.IsSafelyFacing(toUnit(ret), viewDegrees),
                new Action(ret =>
                {
                    WoWUnit unit = toUnit(ret);

                   //if (Settings.DayWalkerSettings.Debug)
                       // Logger.WriteDebug("FaceTarget: facing since more than {0} degrees", (long)viewDegrees);

                    unit.Face();

                    if (!waitForFacing)
                        return RunStatus.Failure;

                    // even though we may want a tighter conical facing check, allow
                    // .. behavior to continue if 150 or better so we can cast while turning
                    if (StyxWoW.Me.IsSafelyFacing(unit, 150f))
                        return RunStatus.Failure;

                    // special handling for when consumed by Direglob and other mobs we are inside/on top of 
                    // .. as facing sometimes won't matter
                    if (StyxWoW.Me.InVehicle)
                    {
                        //Logger.WriteDebug("FaceTarget: don't wait to face {0} since in vehicle", unit.SafeName());
                        return RunStatus.Failure;
                    }

                    // otherwise, indicate behavior complete so begins again while
                    // .. waiting for facing to occur
                    return RunStatus.Success;
                }));
        }
    }
}